package com.wind.trademark.common.dao.impl;



import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import com.wind.trademark.common.dao.BaseDao;
import com.wind.trademark.common.vo.PageBean;
import com.wind.trademark.common.vo.PageParam;



@Repository
public class BaseDaoImpl extends HibernateDaoSupport implements BaseDao {
	private static final Log log = LogFactory.getLog(BaseDao.class);
	@Autowired  
	public JdbcTemplate jdbcTemplate;
	@Autowired  
	public NamedParameterJdbcTemplate namedParameterJdbcTemplate;
	@Autowired  
	public SimpleJdbcTemplate simpleJdbcTemplate;

	@Override
	public SimpleJdbcTemplate getSimpleJdbcTemplate() {
		return simpleJdbcTemplate;
	}
	@Override
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}
	@Override
	public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
		return namedParameterJdbcTemplate;
	}
	
	@Resource(name = "sessionFactory")
	public void setSF(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}

	@Override
	public Serializable  save(Object entity) {
		return super.getHibernateTemplate().save(entity);
	}
	@Override
	public void update(Object entity) {
		super.getHibernateTemplate().update(entity);
	}	
	@Override
	public  void persist(Object entity) {
		 super.getHibernateTemplate().persist(entity);
	}	
	@Override
	public <T extends Serializable>  T merge(T entity) {
		return super.getHibernateTemplate().merge(entity);
	}	
	@Override
	public void saveOrUpdate(Object entity) {
		super.getHibernateTemplate().saveOrUpdate(entity);
	}

	@Override
	public void delete(Object entity) {
		super.getHibernateTemplate().delete(entity);
	}

	@Override
	public <T extends Serializable> T get(Class<T> clazz, Serializable id) {
		// TODO Auto-generated method stub
		return (T) super.getHibernateTemplate().get(clazz, id);
	}

	@Override
	public <T extends Serializable> void saveOrUpdateAll(
			Collection<T> collection) {
		super.getHibernateTemplate().saveOrUpdateAll(collection);
	}

	@Override
	public <T extends Serializable> List<T> findByProperty(Class<T> clazz,
			String propertyName, Object value) {
		log.debug("finding " + clazz.getSimpleName()
				+ " instance with property: " + propertyName + ", value: "
				+ value);
		try {
			String queryString = "from " + clazz.getSimpleName()
					+ " as model where model." + propertyName + "= ?";
			Query queryObject = super.getHibernateTemplate()
					.getSessionFactory().getCurrentSession()
					.createQuery(queryString);
			queryObject.setParameter(0, value);

			@SuppressWarnings("unchecked")
			List<T> list = queryObject.list();
			return list;
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}

	@Override
	public void merge(Object entity) {
		super.getHibernateTemplate().merge(entity);
	}

	@Override
	public <T extends Serializable> List<T> findByExample(T instance) {
		log.debug("finding " + instance.getClass().getSimpleName()
				+ " instance by example");
		try {
			@SuppressWarnings("unchecked")
			List<T> results = super.getHibernateTemplate().getSessionFactory()
					.getCurrentSession().createCriteria(instance.getClass())
					.add(Example.create(instance)).list();
			log.debug("find by example successful, result size: "
					+ results.size());
			return results;
		} catch (RuntimeException re) {
			log.error("find by example failed", re);
			throw re;
		}
	}

	@Override
	public <T extends Serializable> List<T> findByExample(T instance,
			Order... orders) {
		log.debug("finding " + instance.getClass().getSimpleName()
				+ " instance by example ");
		try {

			Criteria criteria = super.getHibernateTemplate()
					.getSessionFactory().getCurrentSession()
					.createCriteria(instance.getClass())
					.add(Example.create(instance));
			for (Order order : orders) {
				criteria.addOrder(order);
			}
			@SuppressWarnings("unchecked")
			List<T> results = criteria.list();
			log.debug("find by example successful, result size: "
					+ results.size());
			return results;
		} catch (RuntimeException re) {
			log.error("find by example failed", re);
			throw re;
		}
	}

	@Override
	public <T extends Serializable> List<T> findAll(Class<T> clazz) {
		log.debug("findAll " + clazz.getSimpleName() + " instance");
		try {
			String queryString = "from " + clazz.getSimpleName() + " as model ";
			Query queryObject = super.getHibernateTemplate()
					.getSessionFactory().getCurrentSession()
					.createQuery(queryString);

			@SuppressWarnings("unchecked")
			List<T> list = queryObject.list();
			return list;
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}
	@Override
	public <T> PageBean queryPageBeanAndMapping(String sql,
			PageParam pageParam, Class<T> clazz,List<Object> params) {
		String countSql = this.getCountSql(sql);
		Integer totalProperty = simpleJdbcTemplate.queryForInt(countSql, params.toArray());
		
		String pagesql = this.getPageSqlWithList(sql);
		params.add(pageParam.getStart());
		params.add(pageParam.getLimit());

		RowMapper<T> rowMapper = ParameterizedBeanPropertyRowMapper.newInstance(clazz);
		List<T> root = simpleJdbcTemplate.query(pagesql, rowMapper, params.toArray());
		return new PageBean(totalProperty, root);
	}
	@Override
	public <T> PageBean queryPageBeanAndMapping(String sql,
			PageParam pageParam, Class<T> clazz, Map<String,Object> params) {
		String countSql = this.getCountSql(sql);
		Integer totalProperty = simpleJdbcTemplate.queryForInt(countSql, params);
		
		String pagesql = this.getPageSqlWithMap(sql);
		Map<String,Object> pageParamMap=new HashMap<String, Object>();
		pageParamMap.putAll(params);
		pageParamMap.put("start", pageParam.getStart());
		pageParamMap.put("limit", pageParam.getLimit());
		
		RowMapper<T> rowMapper = ParameterizedBeanPropertyRowMapper.newInstance(clazz);
		List<T> root = namedParameterJdbcTemplate.query(pagesql,pageParamMap, rowMapper);
		return new PageBean(totalProperty, root);
	}
	@Override
	public  PageBean queryPageBean(String sql,
			PageParam pageParam,  Map<String,Object> params) {
		String countSql = this.getCountSql(sql);
		Integer totalProperty = simpleJdbcTemplate.queryForInt(countSql, params);
		
		String pagesql = this.getPageSqlWithMap(sql);
		Map<String,Object> pageParamMap=new HashMap<String, Object>();
		pageParamMap.putAll(params);
		pageParamMap.put("start", pageParam.getStart());
		pageParamMap.put("limit", pageParam.getLimit());
		
		List<Map<String, Object>> root = namedParameterJdbcTemplate.queryForList(pagesql,pageParamMap);
		return new PageBean(totalProperty, root);
	}
	@Override
	public  PageBean queryPageBean(String sql,
			PageParam pageParam,List<Object> params) {
		String countSql = this.getCountSql(sql);
		Integer totalProperty = simpleJdbcTemplate.queryForInt(countSql, params.toArray());
		
		String pagesql = this.getPageSqlWithList(sql);
		params.add(pageParam.getStart());
		params.add(pageParam.getLimit());

		List<Map<String, Object>> root= simpleJdbcTemplate.queryForList(pagesql, params);
		return new PageBean(totalProperty, root);
	}
	
	private String deleteOrderBy(String sql) {
		int orderByIndex = sql.toUpperCase().lastIndexOf("ORDER BY");
		int lastRightBracket = sql.toUpperCase().lastIndexOf(")");// 防止聚集函数中的order by
		StringBuffer sqlStringBuffer = new StringBuffer();
		sqlStringBuffer.append(sql);
		if (orderByIndex != -1 && lastRightBracket < orderByIndex) {
			sqlStringBuffer.delete(orderByIndex, sql.length());
		}
		return sqlStringBuffer.toString();
	}

	private String getCountSql(String sql) {
		StringBuffer stringBuffer = new StringBuffer(this.deleteOrderBy(sql));
		stringBuffer.insert(0, "SELECT COUNT(*) FROM ( ");
		stringBuffer.append(" ) AS counttabel");
		return stringBuffer.toString();
	}

	private String getPageSqlWithList(String sql) {
		StringBuffer stringBuffer = new StringBuffer(sql);
		stringBuffer.append("  LIMIT ? ,? ");
		return stringBuffer.toString();
	}
	/**
	 * 得到分页的sql语句
	 */
	public String getPageSqlWithMap(String sql) {
		StringBuffer stringBuffer = new StringBuffer(sql);
		stringBuffer.append("  LIMIT :start ,:limit ");
		return stringBuffer.toString();
	}


}
